#!usr/bin/env python
# -*-coding:utf-8 -*-

"""
巨潮其他爬虫的基类, 继承于xtls.basecrawler.BaseCrawler
"""
import sys
import os
import traceback
from copy import deepcopy
import datetime
import psycopg2

from xtls.basecrawler import BaseCrawler
from xtls.timeparser import now

from cleaner import Cleaner
from company_crawler_util import camel_to_underline
from company_crawler_util import InsertError
from company_crawler_util import get_db_config

ROOT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
if ROOT_PATH not in sys.path:
    sys.path.append(ROOT_PATH)


class CompanyCrawler(BaseCrawler):
    def __init__(self, stock_list, logger):
        super(CompanyCrawler, self).__init__(total=0)
        self.stock_list = stock_list
        self.logger = logger
        self.cleaner = Cleaner()
        self.url_format = 'http://www.cninfo.com.cn/information/%s/%s.html'
        self.category = ''
        self.tab_name = ''
        db_config = get_db_config(ROOT_PATH)
        self.conn = psycopg2.connect(database=db_config['db'], host=db_config['host'], port=db_config['port'],
                                     user=db_config['user'], password=db_config['pw'])
        self.cur = self.conn.cursor()
        self.unfinished_id = set()

    COMPANY_INFO_FORMAT = {
        'stock_id': '',
        'stock_code': '',
    }

    def find_company_info_from(self, url):
        result = {}
        return result

    def save(self, data, tab_op):
        method_mapping = {
            'NEW': self.save_update,
            'UPDATE': self.save_update,
            'INSERT': self.save_insert,
            'PRINT': self.save_print,
            'NOTHING': self.save_nothing,
        }
        method = method_mapping.get(tab_op, None)
        if method:
            method(data)
            self._modify_tab_op_to_nothing(data.get('stock_id', None))
        else:
            self.logger.warn('SAVE METHOD ERROR: stockID: %s, tab_op: %s' % (data['stock_id'], tab_op))

    def _modify_tab_op_to_nothing(self, stock_id):
        tab_op_name = '%s_op' % self.tab_name
        sql = 'UPDATE stock set %s=%s WHERE id=%s'
        sql = sql % (tab_op_name, '%s', '%s')
        try:
            self.cur.execute(sql, ('NOTHING', stock_id))
            self.conn.commit()
        except Exception, e:
            self.logger.exception('Non Modify %s to nothing. Error: %s' % (tab_op_name, e.__str__()))
            raise InsertError(e)

    def save_update(self, data):
        pass

    def save_insert(self, data):
        pass

    def save_print(self, data):
        pass

    def save_nothing(self, data):
        pass

    def deal(self, stock):
        self.total += 1
        if self.get_tab_op(stock) == 'NOTHING':
            self.logger.info('%s-%s-%s-NOTHING' % (self.total, stock.stock_code, self.tab_name))
            return

        company_info = deepcopy(self.COMPANY_INFO_FORMAT)
        company_info['stock_id'] = stock.id
        company_info['stock_code'] = stock_code = stock.stock_code
        tab_op = self.get_tab_op(stock)

        stock_market = stock.stock_market
        if type(self.category) != list:
            category_list = [self.category]
        else:
            category_list = self.category
        for category in category_list:
            url = self.url_format % (category, self.get_url_element(stock_market, stock_code))
            company_info.update(self.find_company_info_from(url))
            self.logger.debug('Parse: %s-%s-%s' % (self.total, company_info['stock_code'], self.category))

        try:
            self.save(company_info, tab_op)
            self.logger.info('Save: %s-%s-%s-%s' % (self.total, company_info['stock_code'], self.category, tab_op))
        except InsertError, e:
            self.logger.exception('Non SAVE: %s-%s-%s-%s' % (self.total, company_info['stock_code'], self.category, tab_op))
            self.conn.commit()
            self.unfinished_id.add(stock.id)

    def get_tab_op(self, stock):
        tab_op_name = '%s_op' % self.tab_name
        return stock.__dict__.get(tab_op_name)

    def get_url_element(self, stock_market, stock_code):
        return ''.join([stock_market.strip(), stock_code.strip()])

    def run(self):
        for stock in self.stock_list:
            self.deal(stock)

        self.cur.close()
        self.conn.close()
        self.logger.info('%s--Todo: %d--Unfinished: %d' % (self.category, self.total, len(self.unfinished_id)))

    def get_unfinished_id(self):
        return self.unfinished_id

# ----------------------util------------------------------------------

    def insert_to_db(self, table_name, cleaned_data):
        cleaned_data['updateTime'] = now()
        key_list = [camel_to_underline(key) for key in cleaned_data.keys()]
        table_name = 'company_%s' % table_name
        sql = 'INSERT INTO %s (%s) VALUES (%s)'
        sql = sql % (table_name, ','.join(key_list), ','.join(['%s' for _ in xrange(len(key_list))]))
        try:
            self.cur.execute(sql, cleaned_data.values())
            self.conn.commit()
        except Exception:
            trace = traceback.format_exc()
            raise InsertError(trace)

    def check_lastest(self, cur_date, lastest_date):
        if not cur_date:
            return False
        try:
            res_date = datetime.date(year=int(cur_date[0:4]),
                                     month=int(cur_date[4:6]),
                                     day=int(cur_date[6:]))
        except ValueError:
            return False

        return False if res_date <= lastest_date else True

    def select_current_version_num(self, table_name, stock_id):
        table_name = 'company_%s' % table_name
        sql = 'SELECT MAX(version_num) FROM %s WHERE stock_id = %s'
        sql = sql % (table_name, '%s')
        self.cur.execute(sql, (stock_id, ))
        version_num = self.cur.fetchone()[0]
        return version_num if version_num else 0

    def select_lastest_date(self, table_name, field_name, stock_id, version_num=None):
        table_name = 'company_%s' % table_name
        if version_num:
            sql = 'SELECT MAX(%s) FROM %s WHERE stock_id=%s AND version_num=%s'
            sql = sql % (field_name, table_name, '%s', '%s')
            self.cur.execute(sql, (stock_id, version_num))
        else:
            sql = 'SELECT MAX(%s) FROM %s WHERE stock_id=%s'
            sql = sql % (field_name, table_name, '%s')
            self.cur.execute(sql, (stock_id, ))

        lastest_date = self.cur.fetchone()[0]
        return lastest_date if lastest_date else datetime.date(1949, 10, 1)
# --------------------------------------------